import { ValueStore, PageMaster, Callbacks, Callback } from "maishu-chitu";
import { errors } from "./errors";
import { contextName, defaultAppKey } from "json!websiteConfig";
import websiteConfig = require("json!websiteConfig");

export { guid } from "maishu-chitu-service";

export const ADMIN_APP = 'admin-app';
export const USER_APP = 'user-app';

let appKey = "";
export let urlParams: {
    appKey?: string, token?: string
} = {
    get appKey() {
        return appKey || defaultAppKey;
    },
    set appKey(value) {
        appKey = value;
    }
};

if (location.search)
    urlParams = parseUrlParams(location.search.substr(1));

export function parseUrlParams(query: string) {
    if (!query) throw new Error(`Argument query is null or empty.`);
    if (query[0] == '?')
        query = query.substr(1);

    let match,
        pl = /\+/g,  // Regex for replacing addition symbol with a space
        search = /([^&=]+)=?([^&]*)/g,
        decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); };

    let urlParams: any = {};
    while (match = search.exec(query))
        urlParams[decode(match[1])] = decode(match[2]);

    return urlParams;
}


/** 监听 ValueStore 值的改变 */
export function subscribe<T>(component: React.Component<any, any>, item: ValueStore<T>, callback: (value: T) => void) {
    let func = item.attach(callback);
    let componentWillUnmount = component.componentWillUnmount as () => void;
    component.componentWillUnmount = function () {
        item.remove(func);
        if (componentWillUnmount)
            componentWillUnmount();
    }
}

// let COMPONENT_INFOS = "compoenntInfos";

// export function setComponentInfos(app: object, compoenntInfos: ComponentInfo[]) {
//     app[COMPONENT_INFOS] = compoenntInfos;
// }

// export function getComponentInfos(app: object): ComponentInfo[] {
//     return app[COMPONENT_INFOS];
// }

// let COMPONENT_PATHS = "componentPaths";
// export function setComponentPaths(app: object, value: ComponentPath[]) {
//     app[COMPONENT_PATHS] = value;
// }

// export function getComponentPaths(app: object): ComponentPath[] {
//     return app[COMPONENT_PATHS];
// }




// const orginalStateName = "-setState";
// const stateUpdating = "-stateUpdating";
// const targetComponents = "-targetComponents";
// const targetFields = "-targetFields";

const dataName = "asyncComponentStateData";

interface AsyncComponentStateData {
    targetComponents: React.Component[],
    targetFields: Array<string[]>,
    stateUpdating: Callback,
    orginalSetState: React.Component["setState"]
}

export function asyncComponentState<S extends React.Component<any, any>, T extends React.Component<any, any>>
    (sourceComponent: S, targtComponent: T, ...stateFields: (keyof (T["state"] | S["state"]))[]) {

    if (sourceComponent == null)
        throw errors.argumentNull("sourceComponent");

    if (targtComponent == null)
        throw errors.argumentNull("targtComponent");

    // console.assert(sourceComponent != targtComponent);

    [sourceComponent, targtComponent].forEach(c => {

        let data: AsyncComponentStateData = c[dataName];
        if (data == null) {
            data = c[dataName] = {
                targetComponents: [],
                targetFields: [],
                stateUpdating: Callbacks(),
                orginalSetState: c.setState
            };

            c.setState = function (state, arg2) {
                data.orginalSetState.apply(c, [state, arg2]);
                for (let i = 0; i < data.targetComponents.length; i++) {
                    updateComponentState(data.targetComponents[i], state, data.targetFields[i] as any);
                }
            }
        }
    })

    let sourceData: AsyncComponentStateData = sourceComponent[dataName];
    let targetData: AsyncComponentStateData = targtComponent[dataName];
    if (sourceData.targetComponents.indexOf(targtComponent) >= 0 && targetData.targetComponents.indexOf(sourceComponent) >= 0) {
        return;
    }

    if (sourceData.targetComponents.indexOf(targtComponent) < 0) {
        sourceData.targetComponents.push(targtComponent);
        sourceData.targetFields.push(stateFields as string[]);
    }

    if (targetData.targetComponents.indexOf(sourceComponent) < 0) {
        targetData.targetComponents.push(sourceComponent);
        targetData.targetFields.push(stateFields as string[]);
    }

    updateComponentState(targtComponent, sourceComponent.state, stateFields);
}

function updateComponentState<T extends React.Component<any, any>>
    (targetComponent: T, state: T["state"], stateFields: (keyof T["state"])[]) {

    let sourceState = state;
    let obj = {} as Partial<T["state"]>;
    for (let i = 0; i < stateFields.length; i++) {
        if (sourceState[stateFields[i]] !== undefined) {
            obj[stateFields[i]] = sourceState[stateFields[i]];
        }
    }

    let targetData: AsyncComponentStateData = targetComponent[dataName];
    console.assert(targetData != null);
    let names = Object.getOwnPropertyNames(obj);
    if (names.length > 0) {
        // targetComponent[orginalStateName](obj);
        targetData.orginalSetState.apply(targetComponent, [obj]);
    }

}


export function loadLess(filePath: string) {
    requirejs({ context: contextName }, [`less!${filePath}`], () => {
    })
}

/** 站点路径 */
export function stationPath(path: string) {
    console.assert(requirejs != null);
    let contexts = requirejs.exec("contexts");
    let contextName: string;
    if (websiteConfig.requirejs)
        contextName = websiteConfig.requirejs.context;

    let context: RequireContext = contexts[contextName];
    if (context != null && context.config != null && context.config.baseUrl != null) {
        return `${context.config.baseUrl}${path}`;
    }
    return `${path}`;
}
